package es.udc.cameraar2;

import com.google.zxing.BinaryBitmap;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.Reader;
import com.google.zxing.Result;
import com.google.zxing.ResultPoint;
import com.google.zxing.common.HybridBinarizer;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
import android.graphics.Bitmap.Config;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.util.Log;

@SuppressLint("WrongCall")
public class CustomPreviewCallback implements PreviewCallback{

	protected long timestamp;
	private int timesPerSec;
	private int refreshRate;
	private static int width, height;
	private Canvas c;
	private byte[] mBuffer;
	private static int framewidth, frameheight;
	private float distance = 1;
	private float minx = 0, miny = 0, maxx = 0, maxy = 0;
	private int count = 0;
	private Panel panel;
	protected long timestampCanvas = 0;
	protected long resultTimeStamp = 0;
	
	private int pointsCounter = 0;
	private ThreadGetData thread = null;
	private ResultPoint[] previousResultPoints;
	

	public CustomPreviewCallback(int height, int width, int refresh, Panel panel){
		this.refreshRate = refresh;
		this.height = height;
		this.width = width;
		this.panel = panel;
	}
	
	
	public void onPreviewFrame(byte[] data, Camera arg1) {

		timesPerSec = 10000/refreshRate;
		//Si ha pasado el tiempo de refresco definido calculamos la posicion del QR
		if ((System.currentTimeMillis()-timestamp) > timesPerSec) {
			
			timestamp=System.currentTimeMillis();
			Result result = null;
			
			/*byte[] dataModified = data;
			
			if (pointsCounter == 0) {
				previousResultPoints = new ResultPoint[] { new ResultPoint(0, 0) };
				framewidth = width;
				frameheight = height;
			} else {
				dataModified = calculateSmallFrame(data,previousResultPoints);
			}
			*/
			BinaryBitmap bitmap = createNewBinaryBitmap(data);
									

			/*
			 * Comprobar si va mas rapido con QRCodeReader que con
			 * el Multiformat
			 */
			 Reader reader = new MultiFormatReader();
			//Reader reader = new QRCodeReader();
			
			try {
				result = reader.decode(bitmap);
				// String contents = result.getText();
				// byte[] rawBytes = result.getRawBytes();
				// BarcodeFormat format = result.getBarcodeFormat();
				ResultPoint[] points = result.getResultPoints();
				if (result != null) {
					previousResultPoints = points;
					pointsCounter = 3;
					if (thread==null){
						thread = new ThreadGetData(result.getText());
					}
				}

				// Log.d("CAMERAPREVIEW","#############Valores result    :"+
				// result.getText()+ "     ###########");
				panel.setText(result.getText() + "  -Pcounter: "
						+ pointsCounter);

				/*
				 * Context context = getContext(); int duration =
				 * 50; Toast toast;^
				 */

				// toast = Toast.makeText(context,result.getText(),
				// duration);
				// toast.show();

			} catch (Exception e) {
				Log.d("CAMERAPREVIEW", "Error   :" + e.toString());
				pointsCounter--;
			}
			// }

			Canvas canvas = null;
			try {
				canvas = panel.getHolder().lockCanvas(null);
				canvas.drawColor(0, PorterDuff.Mode.CLEAR);
				synchronized (panel.getHolder()) {
					// Log.d("THREADCANVAS","Llamo a OnDRAW");
					if (canvas != null) {
						timestampCanvas = System.currentTimeMillis();
						panel.onDraw(canvas, result);
						resultTimeStamp = System.currentTimeMillis()-timestamp;
					}
				}
			} finally {
				if (canvas != null)
					panel.getHolder().unlockCanvasAndPost(canvas);
			}
		}
		else count = 2;
	}

	private BinaryBitmap createNewBinaryBitmap(byte[] dataModified) {
		int[] out = new int[framewidth * frameheight];

		CameraFunctions.decodeYUV(out, dataModified,
				framewidth, frameheight);

		Bitmap bMap = Bitmap.createBitmap(out, framewidth,
				frameheight, Config.ARGB_8888);

		LuminanceSource source = new RGBLuminanceSource(bMap);
		BinaryBitmap bitmap = new BinaryBitmap(
				new HybridBinarizer(source));
		return bitmap;
	}

	/*
	 * Points: 0- down-left 1- up-left 2- up-right 3- down right
	 */
	private byte[] calculateSmallFrame(byte[] data, ResultPoint[] points) {

		byte[] smallframe;

		if (points != null) {
			if (points.length > 1) {
				// distance = ResultPoint.distance(points[0],
				// points[1]);

				minx = points[1].getX(); maxx = points[2].getX();
				miny = points[1].getY(); maxy = points[0].getY();												

				int border = (int) (maxx - minx);

				minx = minx - border;
				maxx = maxx + border;
				miny = miny - border;
				maxy = maxy + border;

				if (minx < 0) minx = 0;
				if (miny < 0) miny = 0;
				if (maxx > width) maxx = width;
				if (maxy > height) maxy = height;

				panel.setMinx((int) minx);
				panel.setMaxx((int) maxx);
				panel.setMiny((int) miny);
				panel.setMaxy((int) maxy);

				// Log.i("CAMERAPREVIEW","##########################VALORES PUNTOS  Puntomin:"+minx+"-"+miny+" Max:"+maxx+"-"+maxy+"   minx: "+minx+"   -maxx:"+maxx+"   -miny:"+miny+"   -maxy:"+maxy+"   -width:"+width+"   -height:"+height+"    -frameWidth:"+(int)(maxx-minx)+"    -frameheight:"+(int)(maxy-miny));

				// smallframe = new
				// byte[(int)((maxx-minx+1)*(maxy-miny+1))*3/2];

				
				smallframe = new byte[width * height * 3];

				for (int i = 0; i < (int) (maxy - miny); i++) {
					// Log.i("CAMERAPREVIEW","##########################VALORES COPIA    sourcePos: "+(int)((miny+i)*width+minx)+"   -destPos:"+(int)(maxx-minx)*i+"   -tam:"+(int)(maxx-minx));
					System.arraycopy(data, (int) ((miny + i)
							* width + minx), smallframe,
							(int) (maxx - minx) * i,
							(int) (maxx - minx));

				}

				framewidth = (int) (maxx - minx) + 1;
				frameheight = (int) (maxy - miny) + 1;

				return smallframe;

			} else
				return data;
		} else
			return data;
	}

}
